<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>JavaScript对象</title>
	</head>
	<body>
		<script type="text/javascript">
		/* 相关单词 */
			// proto : n.原型,样机,典型
			// prototype : n. 原型；标准，模范
			// constructor : n. 构造函数；构造器；建造者
		
		/* 对象初始化 */
			var People = {};//创建对象,此对象为单一对象
			People.name = "Lin";
			People.call = function(){
				console.log("My nane is "+this.name);
			}
			
		/* 工厂模式 */
			//缺点: 并不知道对象的数据类型
			var CreateObject = function(name,age){
				var o = new Object();//
				o.name = name;
				o.age = age;
				o.call = function(){
					console.log("My nane is "+this.name);
				}
				return o;//必须要返回该对象
			}
			var person3 = new CreateObject("Lin");
			person3.call();
			
			
		/* 构造函数 */
			//创建抽象化对象
			//缺点: 并不知道对象的数据类型
			var Person = function(name,age,job){
				this.name = name;
				this.age = age;
				this.job = job;
				this.call = function(){
					console.log("My nane is "+this.name);
					console.log("I am "+this.age+" years old.");
					personFunc();
				}
				var personFunc = function(){//定义私有化方法函数,且只能在私有化内使用
					console.log("My jog is "+job+" .");
				}
			}
			//对象的外置添加属性方法
			//创建的每个函数都有一个prototype（原型）属性，这个属性是一个指针，指向函数的原型对象。
			Person.prototype.words = "Hellow!";
			Person.prototype.say = function(){
				console.log(this.words);
			}
			//对象实例化(创建一个实例)
			var person1 = new Person("Lin",13,"student");
			person1.call();
			person1.say();
			console.log(person1.constructor);
			//result
			/* My nane is Lin
			I am 13 years old. 
			Hellow!*/
			
		/* 原型模式 */
			var Person3 = function(){};
			Person3.prototype = {
				constructor: Person3,
				name: "Lin",
				age: 14,
				sayName: function(){
					console.log("My name is "+this.name);
				},
			}
			
		/* 组合使用构造函数模式和原型模式 */
			//组合使用构造函数模式和原型模式，是创建自定义类型的最常见方式。
			//构造函数模式用于定义实例属性，而原型模式用于定义方法和共享的属性。
			//结果，每个实例都会有自己的一份实例属性的副本，但同时又共享着对方法的引用，最大限度的节省了内存。
			var Person2 = function(name,age){
				this.name = name;
				this.age = age;
			};
			Person2.prototype = {
				constructor: Person2,//规定了该对象的数据类型//返回对创建此对象的函数
				job: "student",//实例化对象时会成为公有化//
				sayJob: function(argu){
					console.log("My job is "+argu);
				},
			}
			var person4 = new Person2("Lin",14);
			var arr = new Array();
			console.log(person4.constructor);
			console.log(arr.constructor);
			if(arr.constructor==Array){//用来判定该对象的数据类型
				console.log("This is a Array");
			}
			if(person4.constructor==Person2){
				console.log("This is a Person2");
			}
			
		/* javascript自定义对象参数对象化 */
			var config = {}
			var Person6 = function(config){
				this.name = config.name;
				this.age = config.age;
				this.sex = config.sex;
			}
			Person6.prototype = {
				constructor: Person6,
				sayName: function(){
					console.log("Person6：My name is "+this.name);//注: 这里的this依然是当前的对象
				},
				sayAge: function(){
					
				},
			}
			config = {name:"Lin"};
			var person6_1 = new Person6(config);
			person6_1.sayName();
			
		/* 注: 重点
			1、对象方法包括构造函数中的方法以及构造函数原型上面的方法；
			2、类方法，其实这里的类就是一个函数，在js中由于函数也是一个对象，所以可以为函数添加属性以及方法，这种方法在node中用的比较多；
			3、原型方法一般用于对象实例共享，比如Person.prototype.sayName=function(){console.log(this.name);};在原型上面添加该方法，就能实现共享。
				这样就不用每一次初始化一个实例的时候，为其分配相应的内存了。*/
				
				
		/* js构造函数关于prototype */
			var Animal = function(kind,num){
				this.kind = kind;
				this.num = num;
			}
			Animal.prototype = {
				constructor: Animal,
				getKind: function(){
					console.log("kind:"+this.kind);
				},
				getNum: function(){
					console.log("num:"+this.num);
				},
			}
			var dog = new Animal("dog",6);
			
			console.log("Animal原型：")
			console.log(Animal.prototype);
			console.log("Animal实例：")
			console.log(dog.prototype);
			console.log(Animal.constructor.call(this));// => f anonymous(){}
			//anonymous: adj.匿名的
			
			var Animal2 = function(){
				// this.prototype.constructor = new Animal(num);
			}
			/* 	
			@subClaa:子类
			@superClass:父类*/
			var extend = function(subClass,superClass){
				// var F = function(){ };
				subClass.prototype.constructor = superClass;
				subClass.prototype = superClass.prototype;
				// subClass.prototype = new F();
				console.log(subClass.prototype);
				console.log(subClass.prototype.constructor);
			}
			extend(Animal2,Animal);
			console.log(Animal2);
			
			var dog2 = Animal2("dog",7);
			// dog2.getNum();
			
			console.log(NaN==NaN)
			
		/* ECMAScript5中加入的对象创建 Object.create() */
			/* Object.create(proto,[propertiesObject]) 
				proto: 新创建对象的原型对象
				propertiesObject: 可选。*/
			var objJson = {
				name:"lin",
				age:"22",
			}
			var Me = Object.create(objJson);
			console.log("输出对象Me的name属性："+Me.name);// result: 输出对象Me的name属性：lin
			Me.height = 177;
			console.log('Me的身高是'+Me.height)
			// 有些类似于去继承一个对象.
			
			"use strict"
			Me = Object.create(Object.prototype,{
				foo:{
					writable:true,
					configurable:true,
					value: "hello"
				},
				sss:{//名称是可变的
					configurable:false,
					get: function() { return 10 },
					set: function(value) {
					  console.log("Setting `o.bar` to", value);
					}
				}
			})
			console.log("Me.sss:"+Me.sss); // result: 10
			console.log("Me.foo:"+Me.foo); // result: Me.foo:hello
			console.log("Me.foo:"+Me.foo.value); // result: Me.foo:undefined
		</script>
	</body>
</html>